<script setup>
// import { ref } from 'vue'
// 引入three
import * as THREE from 'three'
// 引入轨道控制器
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
// 引入gltf模型加载库GLTFLoader.js
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
// 引入gltf解析器（压缩过的模型要使用解析器！！！）
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'
import gsap from 'gsap'
import { DemoOne } from '@/stores/index'
let loading = DemoOne()
let vuepage = DemoOne()


// 初始化三维场景
const scene = new THREE.Scene()


// 初始化相机
const camera = new THREE.PerspectiveCamera(
  95,
  window.innerWidth / window.innerHeight,
  0.1,
  1000
)
// 设置相机位置
camera.position.set(49.55024885587635, 20.341654445002185, -61.22524772548634)

// 初始化渲染器
const render = new THREE.WebGLRenderer({
  // 设置抗锯齿
  antialias: true
})
// 设置渲染器大小
render.setSize(window.innerWidth, window.innerHeight)
// 将渲染器放置到body页面中
document.body.appendChild(render.domElement)


// 初始化轨道控制器
const controls = new OrbitControls(camera, render.domElement)
// 开启阻尼效果
controls.enableDamping = true
// 设置阻尼系数
controls.dampingFactor = 0.05
// 限制垂直旋转角度
controls.minPolarAngle = Math.PI / 16
controls.maxPolarAngle = Math.PI / 2
// 设置相机向外移动的最大值
controls.minDistance = 10
controls.maxDistance = 100



// 创建纹理加载器
const textureLoader = new THREE.TextureLoader()
// 加载纹理
let texture = textureLoader.load('./textures/img/scenebackimg.png', () => {
  // 纹理要开启色彩空间(否则颜色会有偏差)
  texture.colorSpace = THREE.SRGBColorSpace
  scene.background = texture
})


// 创建GLTF加载器对象
const gltfLoader = new GLTFLoader()
// 创建解析器对象
const dracoLoader = new DRACOLoader()


// 解析器位置
dracoLoader.setDecoderPath('./draco/')
// 给加载器指定解析器
gltfLoader.setDRACOLoader(dracoLoader)
// 注意！！：默认是在public中找模型，写路径的时候不能再写public
gltfLoader.load('./models/perm_theatre.glb', (gltf) => {
  // 返回的场景对象gltf.scene插入到threejs场景中
  const model = gltf.scene
  model.traverse(child => {
    const edgesgeometry = new THREE.EdgesGeometry(child.geometry)
    const edgesMaterial = new THREE.LineBasicMaterial({
      color: '#0f77c5'
    })
    const edges = new THREE.LineSegments(edgesgeometry, edgesMaterial)
    scene.add(edges)
    // 更新建筑物世界转换矩阵，与原模型重合
    child.updateWorldMatrix(true, true)
    edges.matrix.copy(child.matrixWorld)
    edges.matrix.decompose(edges.position, edges.quaternion, edges.scale)
    // 隐藏原模型所有子网格
    child.visible = false
  })
  scene.add(model)
  // 模型加载完成隐藏加载页
  loading.loadingValue = false
  // 隐藏加载页面后显示组件
  vuepage.vuepage = true
})

gsap.to(camera, {
  fov: 70, // 缩小视角到 30
  duration: 1,
  ease: 'power2.inOut',
  onUpdate: () => {
    camera.updateProjectionMatrix()
  }
})

// 添加平行光
const ligth1 = new THREE.DirectionalLight(0xffffff, 1)
ligth1.position.set(0, 10, 0)
const ligth2 = new THREE.DirectionalLight(0xffffff, 1)
ligth2.position.set(10, 0, 0)
const ligth3 = new THREE.DirectionalLight(0xffffff, 1)
ligth3.position.set(0, 0, 10)
scene.add(ligth1, ligth2, ligth3)


// 设置画布自适应屏幕大小
window.addEventListener('resize', () => {
  // 重置渲染器输出画布canvas尺寸
  render.setSize(window.innerWidth, window.innerHeight)
  // 全屏情况下：设置观察范围长宽比aspect为窗口宽高比
  camera.aspect = window.innerWidth / window.innerHeight
  // 如果相机的一些属性发生了变化，需要执行updateProjectionMatrix ()方法更新相机的投影矩阵
  camera.updateProjectionMatrix()
})

// 使用补间动画移动相机位置
const timeLine1 = gsap.timeline()
const timeLine2 = gsap.timeline()
// 定义相机移动函数
const translateCanera = (position, target) => {
  controls.enabled = false // 禁用控制器
  controls.enableDamping = false // 关闭阻尼效果
  // 要跳转到的位置
  timeLine1.to(camera.position, {
    x: position.x,
    y: position.y,
    z: position.z,
    duration: 1,
    ease: 'power2.inOut'
  }).eventCallback('onComplete', () => {
    controls.enabled = true // 动画完成后再启用控制器
    controls.enableDamping = true // 关闭阻尼效果
  })
  // 跳转时围绕哪个目标旋转
  timeLine2.to(controls.target, {
    x: target.x,
    y: target.y,
    z: target.z,
    duration: 1,
    ease: 'power2.inOut'
  })
}

let iconMeshes = [] // 存储多个图标
const iconTexture = textureLoader.load('./textures/img/icon.png') // 替换为你的图标路径
// 创建平面几何体并添加纹理
const iconGeometry = new THREE.PlaneGeometry(3, 3) // 图标尺寸
const iconMaterial = new THREE.MeshBasicMaterial({
  map: iconTexture,
  transparent: true,
  side: THREE.DoubleSide
})
// 创建多个图标并设置不同的位置
const positions = [
  {
    position: { x: 25, y: 0, z: 0 },
    action: () => {
      translateCanera(new THREE.Vector3(41.910533712488345, 7.599792300931379, -0.660526318471674), new THREE.Vector3(0, 0, 0))
    }
  },
  {
    position: { x: -25, y: 0, z: 0 },
    action: () => {
      translateCanera(new THREE.Vector3(-42.209956324944486, 5.64138963398451, 1.0864176217889834), new THREE.Vector3(0, 0, 0))
    }
  },
  {
    position: { x: 0, y: 0, z: -25 },
    action: () => {
      translateCanera(new THREE.Vector3(0.24653763112403967, 6.202387167112909, -42.144461152454596), new THREE.Vector3(0, 0, 0))
    }
  },
  {
    position: { x: 0, y: 0, z: 35 },
    action: () => {
      translateCanera(new THREE.Vector3(1.6058089739306418, 1.3825910252932423, 52.257613668833315), new THREE.Vector3(0, 0, 0))
    }
  }

]
positions.forEach((pos, index) => {
  const iconMesh = new THREE.Mesh(iconGeometry, iconMaterial)
  iconMesh.position.set(pos.position.x, pos.position.y, pos.position.z)
  iconMesh.name = `icon_${index}` // 给每个图标一个唯一的名称
  iconMesh.userData = { action: pos.action }
  scene.add(iconMesh)
  iconMeshes.push(iconMesh)
})

// 创建射线
const raycaster = new THREE.Raycaster()
// 创建鼠标向量，用于保存鼠标点在了画布的哪个地方
const mouse = new THREE.Vector2()
// 公共函数：更新鼠标位置并进行射线检测
function updateMouseAndRay(event) {
  // 计算鼠标在屏幕空间中的位置
  mouse.x = (event.clientX / window.innerWidth) * 2 - 1
  mouse.y = -(event.clientY / window.innerHeight) * 2 + 1

  // 将射线投射到场景中
  raycaster.setFromCamera(mouse, camera)

  // 计算射线与物体的交点
  const intersects = raycaster.intersectObjects(iconMeshes)

  // 如果射线与图标相交，触发点击事件
  if (intersects.length > 0 && event.button === 0) {
    // 获取点击的图标
    const clickedIcon = intersects[0].object
    const action = clickedIcon.userData.action
    if (action) {
      action()
    }

  }
}
// 绑定事件监听器
window.addEventListener('click', updateMouseAndRay)

// 初始化时钟
const clock = new THREE.Clock()

// 创建渲染函数
const animate = () => {
  // 请求动画帧
  requestAnimationFrame(animate)

  // 获取时间
  const time = clock.getElapsedTime()

  iconMeshes.forEach((iconMesh) => {
    // 图标朝向相机
    iconMesh.lookAt(camera.position)
    // 图标浮动效果
    iconMesh.position.y = Math.sin(time) * 1
  })

  // 渲染
  render.render(scene, camera)
  controls.update()
}
// 调用渲染函数
animate()


// 获取相机位置+目标位置（保留备用）
const cameraFun = () => {
  // console.log(camera.position.x, camera.position.y, camera.position.z)
  // console.log(controls.target.x, controls.target.y, controls.target.z)
  translateCanera(new THREE.Vector3(49.55024885587635, 20.341654445002185, -41.22524772548634), new THREE.Vector3(0, 0, 0))
}
</script>

<template>
  <div>
    <!-- <button @click="cameraFun">获取坐标</button> -->
    <button v-if="vuepage.vuepage" @click="cameraFun">初始视角</button>
  </div>
</template>

<style lang="scss" scoped>
button {
  position: fixed;
  left: vw(578px);
  top: vh(200px);
  width: vw(147px);
  height: vh(49px);
  background: url('./textures/img/button.png') no-repeat center/100% 100%;
  z-index: 3;
  color: #fff;
  border: none;
  font-size: vw(18px);
  cursor: pointer;
}
</style>